﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace CommonLib {
    public class Screen {
        private Vector3c topLeft;
        private int width, height, length;
        private Vector3c dw, dh;
        private Vector3c eye;
        private Bitmap pixels;
        private Rectangle bmpRect;

        public Screen(int w, int h) {
            Vector3c tl = new Vector3c(-4, 3, 5);
            Vector3c tr = new Vector3c(4, 3, 5);
            Vector3c bl = new Vector3c(-4, -3, 5);
            Vector3c ey = new Vector3c(0, 0, 0);

            //Vector3c pos = new Vector3c( -2, 0, -2 );
            //Vector3c target = new Vector3c( 0, 0.8, 5 );
            Vector3c pos = new Vector3c(0, 0, -5);
            Vector3c dir = new Vector3c(0, 0.5, 5);
            Vector3c up = new Vector3c(0, 1, 0);

            width = w;
            height = h;
            length = w * h;
            pixels = new Bitmap(w, h);
            bmpRect = new Rectangle(0, 0, w, h);

            Vector3c zaxis = dir;
            zaxis.normalize();
            Vector3c yaxis = up;
            yaxis.mac(-up.dot(zaxis), zaxis);
            Vector3c xaxis = yaxis.cross(zaxis);

            Matrix3 revol = new Matrix3(xaxis, yaxis, zaxis);

            eye = revol.mul(ey);
            eye.add(pos);
            //topLeft = tl;
            topLeft = revol.mul(tl);
            topLeft.add(pos);
            tr = revol.mul(tr);
            tr.add(pos);
            bl = revol.mul(bl);
            bl.add(pos);

            //dw = (tr - tl) / w;
            //dh = (bl - tl) / h;
            dw = tr;
            dw.sub(topLeft);
            dw.div(w);
            dh = bl;
            dh.sub(topLeft);
            dh.div(h);
        }
        public Bitmap Buffer {
            get { return this.pixels; }
        }
        public BitmapData Lock() {
            return pixels.LockBits(bmpRect, ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb);
        }
        public void Unlock(BitmapData bmpData) {
            pixels.UnlockBits(bmpData);
        }
        public int Size {
            get { return this.length; }
        }
        public int Width {
            get { return this.width; }
        }
        public int Height {
            get { return this.height; }
        }
        public Ray getRay(int w, int h) {
            //return new Ray(eye, topLeft + (w * dw) + (h * dh) - eye);
            Vector3c direction = topLeft;
            direction.mac(w, dw);
            direction.mac(h, dh);
            direction.sub(eye);
            return new Ray(eye, direction);
        }
        public Ray getRay(int index) {
            return getRay(index % width, index / width);
        }
        public void setPixel(int w, int h, Vector3c color) {
            color.mul(255);
            Color pix = Color.FromArgb(
                (Math.Max(0, Math.Min((int)(color.x), 255))),
                (Math.Max(0, Math.Min((int)(color.y), 255))),
                (Math.Max(0, Math.Min((int)(color.z), 255))));

            lock (this) {
                this.pixels.SetPixel(w, h, pix);
            }
        }
        public void setPixel(int index, Vector3c color) {
            setPixel(index % width, index / width, color);
        }
    }
}
